package com.tk.exam.interceptor;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.tk.exam.domain.TkToken;
import com.tk.exam.http.Response;
import com.tk.exam.service.TkTokenService;
import com.tk.exam.utils.TokenThreadUtil;
import com.tk.exam.utils.TraceLogUtils;
import com.tk.exam.utils.constant.Constants;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Map;


@Slf4j
@Component
public class RequestHeaderValidatorInterceptor implements HandlerInterceptor {

    private static final String APPLICATION_CHARSET = "application/json;charset=utf-8";

    @Autowired
    TkTokenService tkTokenService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        MDC.put(Constants.LOG_TRACE_ID, TraceLogUtils.getTraceId());

        if (handler.getClass().isAssignableFrom(HandlerMethod.class)) {//如果是spring mvc 方法
            NoCheckHttpHeader noIntercept = ((HandlerMethod) handler).getMethodAnnotation(NoCheckHttpHeader.class);
            if (noIntercept != null) {
                return true;
            }
            String token = request.getHeader("token");
            if (StringUtils.isEmpty(token)) {
                return responseFail(response, "请设置请求头token");
            }
            TkToken tkToken = tkTokenService.getToken(token);
            if (tkToken == null || tkToken.getIsExpired() == 1 || checkExpireTime(tkToken)) {
                //过期
                if (tkToken != null) {
                    tkTokenService.removeToken(tkToken);
                }
                return responseFail(response, "token不存在或已失效");
            }
            if (request.getRequestURI().contains("admin")) {
                Map<String, Object> tokenInfoMap = JSONObject.parseObject(tkToken.getTokenInfo());
                String loginType = (String) tokenInfoMap.get("loginType");
                if (!"admin".equals(loginType)) {
                    return responseFail(response, "无权限访问");
                }
            }
            //续期
            tkTokenService.delayToken(tkToken);
            TokenThreadUtil.setTkToken(tkToken);
        }
        return true;
    }


    private boolean responseFail(HttpServletResponse response, String message) throws IOException {
        ServletOutputStream out = response.getOutputStream();
        response.setCharacterEncoding("UTF-8");
        response.setContentType(APPLICATION_CHARSET);
        Response res = Response.fail(message);
        out.write(JSON.toJSONString(res).getBytes("UTF-8"));
        out.flush();
        return false;
    }

    private boolean checkExpireTime(TkToken tkToken) {
        Instant instant = tkToken.getExpireTime().toInstant();
        ZoneId zone = ZoneId.systemDefault();
        LocalDateTime expireDateTime = LocalDateTime.ofInstant(instant, zone);
        LocalDateTime localDateTime = LocalDateTime.now();
        return localDateTime.isBefore(expireDateTime) ? false : true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 最后执行MDC删除
        MDC.clear();
    }

}
